package tenant

import (
	"context"
	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/text/gstr"
	"github.com/gogf/gf/v2/util/gconv"
	"ruoyi-vue-pro-go/api/common"
	v1 "ruoyi-vue-pro-go/api/tenant/v1"
	"ruoyi-vue-pro-go/internal/consts"
	"ruoyi-vue-pro-go/internal/dao"
	"ruoyi-vue-pro-go/internal/model/do"
	"ruoyi-vue-pro-go/internal/model/entity"
	"ruoyi-vue-pro-go/internal/service"
	"ruoyi-vue-pro-go/utility/excel"
)

type (
	sTenant struct{}
)

func init() {
	service.RegisterTenant(New())
}

func New() service.ITenant {
	return &sTenant{}
}

func (s *sTenant) GetList(ctx context.Context, req *v1.GetListReq) (res *v1.GetListRes, err error) {
	res = &v1.GetListRes{}
	err = dao.SystemTenant.Ctx(ctx).Scan(&res.List)
	return
}

func (s *sTenant) GetOne(ctx context.Context, req *v1.GetOneReq) (res *v1.GetOneRes, err error) {
	res = &v1.GetOneRes{}
	err = dao.SystemTenant.Ctx(ctx).Where(do.SystemTenant{
		Id: req.Id,
	}).Scan(&res.SystemTenant)
	return
}

func (s *sTenant) GetByWebsite(ctx context.Context, req *v1.GetByWebsiteReq) (res *v1.GetByWebsiteRes, err error) {
	res = &v1.GetByWebsiteRes{}
	err = dao.SystemTenant.Ctx(ctx).Where(do.SystemTenant{
		Website: req.Website,
	}).Scan(&res.SystemTenant)
	return
}

func (s *sTenant) GetPage(ctx context.Context, req *v1.GetPageReq) (res *v1.GetPageRes, err error) {
	res = &v1.GetPageRes{
		List:          make([]*entity.SystemTenant, 0),
		CommonPageRes: &common.CommonPageRes{},
	}
	model := dao.SystemTenant.Ctx(ctx)
	if req.Name != "" {
		model = model.WhereLike("name", "%"+req.Name+"%")
	}
	if req.ContactName != "" {
		model = model.WhereLike("contact_name", "%"+req.ContactName+"%")
	}
	if req.ContactMobile != "" {
		model = model.WhereLike("contact_mobile", "%"+req.ContactMobile+"%")
	}
	if req.Status != -1 {
		model = model.Where("status", req.Status)
	}
	// 添加时间范围条件
	if len(req.CreateTime) != 0 {
		beginTime := gtime.New(req.CreateTime[0])
		endTime := gtime.New(req.CreateTime[1])
		if beginTime != nil && endTime != nil {
			// 验证时间顺序
			if beginTime.Time.After(endTime.Time) {
				return nil, gerror.New("开始时间不能晚于结束时间")
			}

			model = model.WhereBetween("create_time", beginTime, endTime)
		} else if beginTime != nil {
			model = model.WhereGTE("create_time", beginTime)
		} else if endTime != nil {
			model = model.WhereLTE("create_time", endTime)
		}
	}
	if req.PageSize != 0 {
		res.PageNo = req.PageNo
		res.PageSize = req.PageSize
		model = model.Page(req.PageNo, req.PageSize)
	}
	err = model.ScanAndCount(&res.List, &res.Total, false)
	return
}

func (s *sTenant) GetIdByName(ctx context.Context, req *v1.GetIdByNameReq) (res *v1.GetIdByNameRes, err error) {
	res = &v1.GetIdByNameRes{}
	record, err := dao.SystemTenant.Ctx(ctx).Fields("id").Where(do.SystemTenant{
		Name: req.Name,
	}).One()
	if err != nil || record.IsEmpty() {
		return nil, gerror.NewCode(gcode.CodeNotFound, "tenant not found")
	}
	res.Id = record["id"].Uint()
	return
}

func (s *sTenant) Update(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error) {
	res = &v1.UpdateRes{}
	_, err = dao.SystemTenant.Ctx(ctx).Data(req).Where(do.SystemTenant{
		Id: req.Id,
	}).Update()
	if err != nil {
		return nil, gerror.NewCode(gcode.CodeDbOperationError, "tenant update failed")
	}
	return
}

func (s *sTenant) Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error) {
	res = &v1.CreateRes{}
	var cls = dao.SystemTenant.Columns()
	count, err := dao.SystemTenant.Ctx(ctx).
		Where(cls.Name, req.Name).
		Where(cls.ContactMobile, req.ContactMobile).
		Where(cls.Website, req.Website).Count()
	if err != nil {
		return res, err
	}
	if count > 0 {
		return res, gerror.NewCode(gcode.CodeDbOperationError, "租户已存在")
	}
	_, err = dao.SystemTenant.Ctx(ctx).Data(req).Insert()
	if err != nil {
		return res, gerror.NewCode(gcode.CodeDbOperationError, "tenant create failed")
	}
	return
}

func (s *sTenant) Delete(ctx context.Context, req *v1.DeleteReq) (res *v1.DeleteRes, err error) {
	res = &v1.DeleteRes{}
	var cls = dao.SystemTenant.Columns()
	_, err = dao.SystemTenant.Ctx(ctx).Where(cls.Id, req.Id).Delete()
	if err != nil {
		return nil, gerror.NewCode(gcode.CodeDbOperationError, "tenant delete failed")
	}
	return
}

func (s *sTenant) DeleteList(ctx context.Context, req *v1.DeleteListReq) (res *v1.DeleteListRes, err error) {
	res = &v1.DeleteListRes{}
	var cls = dao.SystemTenant.Columns()
	// 参数转换
	ids := gconv.Ints(gstr.Split(req.Ids, ","))
	if len(ids) == 0 {
		return nil, gerror.New("无效的ID参数")
	}
	_, err = dao.SystemTenant.Ctx(ctx).WhereIn(cls.Id, ids).Delete()
	if err != nil {
		return nil, gerror.NewCode(gcode.CodeDbOperationError, "tenant delete list failed")
	}
	return
}

func (s *sTenant) ExportExcel(ctx context.Context, req *v1.ExportExcelReq) (res *v1.ExportExcelRes, err error) {
	res = &v1.ExportExcelRes{}
	// 1. 获取租户数据
	tenantList, err := service.Tenant().GetList(ctx, &v1.GetListReq{})
	if err != nil {
		return nil, gerror.Wrap(err, "获取租户数据失败")
	}

	// 2. 创建导出器
	exporter := excel.NewGenericExporter(
		"租户列表.xlsx",
		tenantList.List,
		excel.WithFields(consts.TenantExportFieldsOrder...),
		excel.WithHeaderMap(consts.TenantExportFields),
	)

	// 3. 执行导出
	r := ghttp.RequestFromCtx(ctx)
	if err := exporter.Export(ctx, r.Response); err != nil {
		return nil, gerror.Wrap(err, "导出租户列表失败")
	}

	// 4. 终止后续处理
	r.ExitAll()
	return nil, nil
}
